package com.xilihui.xlh.core.crash;

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.os.Process;
import android.util.Log;

import com.xilihui.xlh.core.app.BaseApplication;
import com.xilihui.xlh.core.util.LogUtil;
import com.xilihui.xlh.core.util.ToastUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * 未捕获的异常
 * 未捕获的异常，即没有进行try...catch...的异常，会导致闪退
 * 自定义未捕获的异常，可以对异常信息进行处理，如保存、上传崩溃日志，自定义闪退友好界面等
 */
public class CrashExceptionHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "AndroidRuntime";

    /**
     * 单例模式
     */
    private static CrashExceptionHandler instance = new CrashExceptionHandler();

    private CrashExceptionHandler() {
    }

    public static CrashExceptionHandler getInstance() {
        return instance;
    }

    /**
     * 初始化
     */
    public void init() {
        // 替换系统默认的未捕获异常类
        Thread.setDefaultUncaughtExceptionHandler(instance);
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // 未捕获的异常会出现在这里
        LogUtil.e("uncaughtException" + " " + Thread.currentThread().getName());
        // 打印并保存异常日志
        save(e);
        // 异常提醒
        remind();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        Process.killProcess(Process.myPid());
        System.exit(0);
    }

    private void remind() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                ToastUtil.toastException();
                Looper.loop();
            }
        }).start();
    }

    private void save(Throwable ex) {
        StringBuilder exceptionStr = new StringBuilder();
        PackageInfo packageInfo = getPackageInfo(BaseApplication.get().getPackageName());
        exceptionStr.append("App Version：").append(packageInfo.versionName).append("\n")//版本信息
                .append("OS Version：").append(Build.VERSION.RELEASE)//手机系统信息
                .append(" SDK ").append(Build.VERSION.SDK_INT).append("\n")//手机系统信息
                .append("Vendor: ").append(Build.MANUFACTURER).append("\n")//手机制造商
                .append("Model: ").append(Build.MODEL).append("\n");//手机型号
        String stackTraceString = Log.getStackTraceString(ex);
        LogUtil.e("AndroidRuntime", exceptionStr.toString() + stackTraceString);
        saveExceptionToSdcard(exceptionStr.toString() + stackTraceString);
    }

    private void saveExceptionToSdcard(String errorReason) {
        // 添加写权限
        // SDK 21 以上动态请求权限
        FileOutputStream fos = null;
        try {
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                DateFormat mFormatter = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss", Locale.getDefault());
                String time = mFormatter.format(new Date());
                String fileName = "Crash_" + time + ".log";
                String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/QianRuiJi/crash/";
                File dir = new File(path);
                if (!dir.exists()) {
                    if (!dir.mkdirs()) {
                        return;
                    }
                }
                fos = new FileOutputStream(path + fileName);
                fos.write(errorReason.getBytes());
                fos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取App安装包信息
     *
     * @return PackageInfo
     */
    private PackageInfo getPackageInfo(String packageName) {
        PackageInfo info = null;
        try {
            info = BaseApplication.get().getPackageManager().getPackageInfo(packageName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return info;
    }
}
